package com.tuling.nettyWebSocketClient;

import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public abstract class AbstractWebsocketClient implements AutoCloseable {
    private static final Logger log = LoggerFactory.getLogger(AbstractWebsocketClient.class);

    /**
     * 接受相应的超时时间
     */
    private final int connectionTimeOut;

    /**
     * 任务上下文
     */
    protected WebsocketContext websocketContext;

    public AbstractWebsocketClient(int connectionTimeOut) {
        this.connectionTimeOut = connectionTimeOut;
        this.websocketContext = new WebsocketContext(new Semaphore(1));
    }

    /**
     * 发送信息
     *
     * @param message
     */
    public void write(String message) {
        Channel channel = getChannel();
        if (channel != null) {
            channel.writeAndFlush(new TextWebSocketFrame(message));
        } else {
            throw new RuntimeException("连接已关闭");
        }
    }

    public void connect() throws Exception {
        try {
            doOpen();
            doConnect();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("连接没有成功");
        }
    }

    public String receiveResult() throws Exception {
        this.receive(this.websocketContext.getLock());
        if (StringUtils.isEmpty(this.websocketContext.getResult())) {
            throw new RuntimeException("没有获取到任务结果信息");
        } else {
            return this.websocketContext.getResult();
        }
    }

    private void receive(Semaphore lock) throws Exception {
        boolean waitFlag = false;
        try {
            waitFlag = lock.tryAcquire(connectionTimeOut, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            log.info("此链接未收到响应信息");
            Thread.currentThread().interrupt();
        }
        if (!waitFlag) {
            log.error("Timeout {}s when receiving response message", connectionTimeOut);
            throw new RuntimeException("此连接未收到响应信息");
        }
    }

    protected abstract void doOpen();

    protected abstract void doConnect() throws Exception;

    /**
     * 本次连接的channel
     *
     * @return
     */
    protected abstract Channel getChannel();

    public abstract void close();
}
